import 'reflect-metadata'

interface ModuleMetaData {
    controllers?: Function[];
    providers?: any[];
    exports?: any[];     // 模块的导出 可以把自己的一部分providers导出给别的模块，其他模块只要导入了自己这个模块
    imports?: any[];     // 模块的导入 可以导入其他模块，把其他模块的导出的providers给自己用
}

export function Module(metadata: ModuleMetaData): ClassDecorator {
    return (target: Function) => {
        // 当一个类使用Module装饰器的时候就可以添加标识他是一个模块的元数据
        Reflect.defineMetadata('isModule', true, target);
        // 吧控制器的类和提供者的类和对应的模块进行了关联
        defineModule(target, metadata.controllers ?? []);
        // 给模块类添加 元数据AppModule,元数据的名字叫做controllers，值是controllers数组[AppController]
        Reflect.defineMetadata('controllers', metadata.controllers, target);
        // 给模块类AppModule添加元数据，providers，值是 [LoggerService]
        Reflect.defineMetadata('providers', metadata.providers, target);
        // 在类上保存一个provider数组，标识此模块注入的provider供应者
        // let providers = (metadata.providers ?? []).filter(Boolean).map((provider)=>{
        //     if(provider instanceof Function){
        //         return provider
        //     }else if(provider.useClass instanceof Function){
        //         return provider.useClass
        //     }else{
        //         return null
        //     }
        // }).filter(Boolean)
        // defineModule(target, metadata.providers ?? []);
        defineModule(target, (metadata.providers ?? []).map((provider:any)=>{
            if(provider?.useClass) return provider.useClass;
            if(provider instanceof Function) return provider;
        }).filter(Boolean));
        // 在类上保存exports
        Reflect.defineMetadata('exports', metadata.exports, target);
        // 在类上保存imports
        Reflect.defineMetadata('imports', metadata.imports, target);
    }
}

// 需要知道控制器是哪个providers
export function defineModule(nestModule, targets = []) {
    // 遍历targets数组，为每一个元素添加元数据，key是nestModule，value是nestModule
    targets.forEach(target => {
        Reflect.defineMetadata('nestModule', nestModule, target);
    })
}

export function Global() {
    return (target: Function) => {
        Reflect.defineMetadata('global', true, target);
    }
}

export interface DynamicModule extends ModuleMetaData {
    module:Function,
}
